package com.geek.common.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT 工具类（基于 Auth0 Java-JWT）
 * 功能：生成 Token、解析 Token、验证 Token、获取 Claims
 * 版本：Auth0 Java-JWT 4.4.0+
 */
public class JwtUtils {

    // ==================== 配置参数 ====================
    private static final String SECRET_KEY = "your-256-bit-secret-key-must-be-at-least-32-chars";
    private static final long EXPIRATION_TIME = 86400000; // Token 过期时间（默认 24 小时，单位：毫秒）
    private static final String ISSUER = "geek-system";  // Token 签发者标识
    private static final String AUTH_HEADER = "Authorization"; // HTTP请求头字段名
    private static final String TOKEN_PREFIX = "Bearer "; // Token前缀
    private static final Algorithm ALGORITHM = Algorithm.HMAC256(SECRET_KEY); // 签名算法

    // ==================== 公有方法 ====================

    /**
     * 生成 JWT Token
     * @param claims 自定义 Claims（需包含至少一个非敏感信息，如用户ID、角色等）
     * @return 生成的 Token 字符串
     * @throws IllegalArgumentException 如果 claims 为空或包含敏感信息（如密码）
     */
    public static String generateToken(Map<String, String> claims) {
        if (claims == null || claims.isEmpty()) {
            throw new IllegalArgumentException("Claims 不能为空");
        }

        return JWT.create()
                .withIssuer(ISSUER)                     // 设置签发者
                .withSubject("user-auth")                // 设置主题（可选）
                .withIssuedAt(new Date())                // 设置签发时间
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) // 设置过期时间
                .withClaim("userId", claims.get("userId")) // 添加用户ID
                .withClaim("role", claims.get("role"))    // 添加用户角色
                // 可继续添加其他自定义 Claims
                .sign(ALGORITHM);                        // 使用算法签名
    }

    /**
     * 从HTTP请求头中解析Token（不验证签名，仅解码）
     * @param request HTTP请求对象
     * @return 解码后的 DecodedJWT 对象，如果未找到Token或格式错误则返回null
     */
    public static DecodedJWT parseToken(HttpServletRequest request) {
        String token = extractToken(request);
        if (token == null) {
            return null;
        }
        try {
            return JWT.decode(token);
        } catch (Exception e) {
            System.err.println("解析Token失败: " + e.getMessage());
            return null;
        }
    }

    /**
     * 直接解析Token字符串（不验证签名，仅解码）
     * @param token JWT Token 字符串
     * @return 解码后的 DecodedJWT 对象
     * @throws com.auth0.jwt.exceptions.JWTDecodeException 如果 Token 格式无效
     */
    public static DecodedJWT parseToken(String token) {
        return JWT.decode(token);
    }

    /**
     * 验证 Token 有效性（包括签名和过期时间）
     * @param token JWT Token 字符串
     * @return true 如果 Token 有效，false 如果无效
     */
    public static boolean validateToken(String token) {
        try {
            JWTVerifier verifier = buildVerifier();
            verifier.verify(token);
            return true;
        } catch (JWTVerificationException e) {
            System.err.println("[JWT 验证失败] " + e.getMessage());
            return false;
        }
    }

    /**
     * 从HTTP请求头中获取指定 Claim 的值
     * @param request   HTTP请求对象
     * @param claimName Claim 名称
     * @return Claim 值的字符串形式（如果不存在或未找到Token返回 null）
     */
    public static String getClaim(HttpServletRequest request, String claimName) {
        DecodedJWT jwt = parseToken(request);
        if (jwt == null) {
            return null;
        }
        return jwt.getClaim(claimName).asString();
    }

    /**
     * 从 Token 中获取指定 Claim 的值
     * @param token     JWT Token 字符串
     * @param claimName Claim 名称
     * @return Claim 值的字符串形式（如果不存在返回 null）
     */
    public static String getClaim(String token, String claimName) {
        DecodedJWT jwt = parseToken(token);
        return jwt.getClaim(claimName).asString();
    }

    // ==================== 私有方法 ====================

    /**
     * 从HTTP请求头中提取Token
     * @param request HTTP请求对象
     * @return 提取的Token字符串（不含前缀），如果未找到则返回null
     */
    private static String extractToken(HttpServletRequest request) {
        String authHeader = request.getHeader(AUTH_HEADER);
        if (authHeader == null || !authHeader.startsWith(TOKEN_PREFIX)) {
            return null;
        }
        return authHeader.substring(TOKEN_PREFIX.length());
    }

    /**
     * 构建 JWT 验证器（复用对象提升性能）
     */
    private static JWTVerifier buildVerifier() {
        return JWT.require(ALGORITHM)
                .withIssuer(ISSUER)  // 验证签发者
                .build();
    }
    // ==================== 测试用例 ====================
    public static void main(String[] args) {
        // 1. 生成测试数据
        Map<String, String> claims = new HashMap<>();
        claims.put("userId", "10001");
        claims.put("role", "admin");

        // 2. 生成 Token
        String token = generateToken(claims);
        System.out.println("生成的 Token: \n" + token);

        // 3. 解析 Token（不验证）
        DecodedJWT jwt = parseToken(token);
        System.out.println("\n解析结果:");
        System.out.println("用户ID: " + jwt.getClaim("userId").asString());
        System.out.println("用户角色: " + jwt.getClaim("role").asString());
        System.out.println("签发时间: " + jwt.getIssuedAt());
        System.out.println("过期时间: " + jwt.getExpiresAt());

        // 4. 验证 Token
        System.out.println("\n验证结果: " + validateToken(token));

        // 5. 测试无效 Token
        String invalidToken = token + "tampered";
        System.out.println("篡改后的 Token 验证: " + validateToken(invalidToken));
    }
}